package io.kimmking.common.zookeeper.dlock;

import cn.hutool.core.util.ObjectUtil;
import io.kimmking.common.zookeeper.properties.ZookeeperProperty;
import io.kimmking.dubbo.common.unit.ThrowableActionV2;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public abstract class AbstractZKDistributedLock{

    protected ZooKeeper zk;

    protected final static String root = "/zklocks";

    protected final static byte[] data = new byte[0];

    /**
     * 用来同步等待zkClient连接到zk服务端
     */
    private final CountDownLatch connectedSignal = new CountDownLatch(1);

    public AbstractZKDistributedLock(ZookeeperProperty property) {
        ThrowableActionV2.execute(() -> {
            zk = new ZooKeeper(property.getConnectURL(), property.getSessionTimeout(), watchedEvent -> {
                if (watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    connectedSignal.countDown();
                }
            });
            //等待zk连接建立完毕
            connectedSignal.await();
            Stat stat = zk.exists(root, false);
            if (ObjectUtil.isNull(stat)) {
                //创建root根节点(永久节点)
                zk.create(root, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        });
    }

    /**
     * 类似于lock()方法
     */
    protected abstract boolean acquire(String key, long leaseTime, TimeUnit unit) throws Exception;

    /**
     * 类似于tryLock()方法
     */
    protected abstract boolean tryAcquire(String key, long waitTime, long leaseTime, TimeUnit unit) throws Exception;

    /**
     * 类似于释放锁的方法
     * @return 返回锁是否释放成功
     */
    protected abstract boolean unAcquire(final String lock);
}